/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package app.net.client;

import app.game.FighterEntity;
import app.game.GlobalStatics;
import app.net.messages.InputMessage;
import app.net.messages.SyncMessage;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferStrategy;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * receive input, send input, paint
 *
 * @author skyr
 */
public class ClientGameLoop extends Canvas implements Runnable {

    private Socket socket;
    private ObjectOutputStream objectOutputStream;
    private boolean running = true;
    //movement booleans
    private boolean leftClickPressed = false;
    private boolean rightClickPressed = false;
    private boolean leftPressed = false;
    private boolean rightPressed = false;
    private boolean jumpPressed = false;
    private int id;
    //fighter entities
    private FighterEntity leftFighter;
    private FighterEntity rightFighter;
    //health bars
    private Rectangle leftHealthBar;
    private Rectangle rightHealthBar;
    //used for drawing
    private BufferStrategy strategy;
    //window
    private JFrame container;
    //contains received messages from server per client id
    private HashMap<Integer, SyncMessage> syncMap;
    private final int healthbarHeight = 20;

    public ClientGameLoop(Socket socket) {
        this.socket = socket;
        /*
         * initialize output stream, window, key and mouse listeners, graphics
         * and entities
         */
        try {
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
        } catch (IOException ex) {
            Logger.getLogger(ClientGameLoop.class.getName()).log(Level.SEVERE, null, ex);
        }
        initWindow();
        addKeyListener(new KeyInputHandler());
        addMouseListener(new MouseInputAdapter());
        requestFocus();
        initGraphics();
        initEntities();
        syncMap = new HashMap<Integer, SyncMessage>();
    }

    public void setSyncMessage(SyncMessage sm) {
        syncMap.put(sm.getId(), sm);
    }

    /**
     * used in new match
     */
    public void resetSyncMap() {
        syncMap = new HashMap<Integer, SyncMessage>();
    }

    public void setId(int id) {
        this.id = id;
    }

    private void initWindow() {
        container = new JFrame("New Game!!!!!");

        JPanel panel = (JPanel) container.getContentPane();
        panel.setPreferredSize(new Dimension(GlobalStatics.W_WIDTH + 10, GlobalStatics.W_HEIGHT));
        panel.setLayout(null);

        setBounds(0, 0, GlobalStatics.W_WIDTH, GlobalStatics.W_HEIGHT);
        panel.add(this);
        panel.setAlignmentX(CENTER_ALIGNMENT);
        panel.setAlignmentY(CENTER_ALIGNMENT);

        setIgnoreRepaint(true);

        container.setLocation(100, 150);
        container.pack();
        container.setResizable(false);
        container.setVisible(true);

        container.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });

    }

    private void initGraphics() {
        createBufferStrategy(2);
        strategy = getBufferStrategy();
    }

    public final void initEntities() {
        // initialize and set positions to entities and health bars
        leftFighter = new FighterEntity(null, 50, 50, false);
        rightFighter = new FighterEntity(null, GlobalStatics.W_WIDTH - 50 - 60, 50, true);
        leftHealthBar = new Rectangle(GlobalStatics.maxHealthPoints * 9, healthbarHeight);
        leftHealthBar.setLocation(5, 5);
        rightHealthBar = new Rectangle(GlobalStatics.maxHealthPoints * 9, healthbarHeight);
        rightHealthBar.setLocation(GlobalStatics.W_WIDTH - (GlobalStatics.maxHealthPoints * 9) - 5, 5);
    }

    @Override
    public void run() {
        long lastLoopTime = System.currentTimeMillis();
        while (running) {
            long delta = System.currentTimeMillis() - lastLoopTime;
            lastLoopTime = System.currentTimeMillis();

            Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();

            //bg color
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, GlobalStatics.W_WIDTH, GlobalStatics.W_HEIGHT);

            //send to server
            try {
                InputMessage im = new InputMessage(
                        leftClickPressed,
                        rightClickPressed,
                        leftPressed,
                        rightPressed,
                        jumpPressed,
                        delta);
//                System.out.println(id + " sending: " + leftPressed + rightPressed);
                objectOutputStream.writeObject(im);
                objectOutputStream.flush();
            } catch (IOException ex) {
                Logger.getLogger(ClientGameLoop.class.getName()).log(Level.SEVERE, null, ex);
            }

            // iterate sync messages and set values in entities
            for (Iterator<SyncMessage> it = syncMap.values().iterator(); it.hasNext();) {
                SyncMessage sm = it.next();
                if (sm.getIsRight()) {
                    rightFighter.setX(sm.getX());
                    rightFighter.setY(sm.getY());
                    if (sm.getIsAtk()) {
                        rightFighter.setIsAtk(true);
                        rightFighter.attack();
                    } else {
                        rightFighter.setIsAtk(false);
                        rightFighter.look();
                    }
                    rightFighter.setIsDef(sm.getIsDef());
                    rightFighter.setHealthPoints(sm.getHealth());
                } else {
                    leftFighter.setX(sm.getX());
                    leftFighter.setY(sm.getY());
                    if (sm.getIsAtk()) {
                        leftFighter.setIsAtk(true);
                        leftFighter.attack();
                    } else {
                        leftFighter.setIsAtk(false);
                        leftFighter.look();
                    }
                    leftFighter.setIsDef(sm.getIsDef());
                    leftFighter.setHealthPoints(sm.getHealth());
                }
            }

            //paint
            leftFighter.draw(g2d);
            rightFighter.draw(g2d);
            g2d.setColor(Color.red);
            leftHealthBar.setSize((leftFighter.getHealthPoints() * 9), (int) leftHealthBar.getHeight());
            rightHealthBar.setSize((rightFighter.getHealthPoints() * 9), (int) leftHealthBar.getHeight());
            rightHealthBar.setLocation(GlobalStatics.W_WIDTH - ((rightFighter.getHealthPoints() * 9)) - 5, 5);
            g2d.fill(leftHealthBar);
            g2d.fill(rightHealthBar);

            // clear up the graphics
            // and flip the buffer over
            g2d.dispose();
            strategy.show();

            //finally pause for a bit
            try {
                Thread.sleep(GlobalStatics.gameTick);
            } catch (Exception e) {
            }
        }
    }

    public void stop() {
        running = false;
    }

    public void start() {
        Thread t = new Thread(this);
        t.start();
    }

    //<editor-fold defaultstate="collapsed" desc="input handling">
    private class MouseInputAdapter extends MouseAdapter {
        
        @Override
        public void mousePressed(MouseEvent e) {
            super.mousePressed(e);
            if (e.getButton() == MouseEvent.BUTTON1) {
                leftClickPressed = true;
            } else if (e.getButton() == MouseEvent.BUTTON2) {
                rightClickPressed = true;
            }
        }
        
        @Override
        public void mouseReleased(MouseEvent e) {
            super.mouseReleased(e);
            if (e.getButton() == MouseEvent.BUTTON1) {
                leftClickPressed = false;
            } else if (e.getButton() == MouseEvent.BUTTON2) {
                rightClickPressed = false;
            }
        }
    }
    
    private class KeyInputHandler extends KeyAdapter {
        
        @Override
        public void keyPressed(KeyEvent e) {
            super.keyPressed(e);
            if (e.getKeyCode() == KeyEvent.VK_A) {
                leftPressed = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_D) {
                rightPressed = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                jumpPressed = true;
            }
            if (e.getKeyCode() == KeyEvent.VK_W) {
                jumpPressed = true;
            }
            
        }
        
        @Override
        public void keyReleased(KeyEvent e) {
            super.keyReleased(e);
            
            if (e.getKeyCode() == KeyEvent.VK_A) {
                leftPressed = false;
            }
            if (e.getKeyCode() == KeyEvent.VK_D) {
                rightPressed = false;
            }
            if (e.getKeyCode() == KeyEvent.VK_SPACE) {
                jumpPressed = false;
            }
            if (e.getKeyCode() == KeyEvent.VK_W) {
                jumpPressed = false;
            }
        }
        
        @Override
        public void keyTyped(KeyEvent e) {
            super.keyTyped(e);
            if (e.getKeyChar() == 27) {//esc
                System.exit(0);
            }
        }
    }
    //</editor-fold>
}
